package cn.jane.rpc.netty.serialize;

import cn.jane.rpc.api.spi.ServiceSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.HashMap;
import java.util.Map;

/**
 * 序列化的支持类
 */
public class SerializeSupport {

    private static final Logger log = LoggerFactory.getLogger(SerializeSupport.class);

    /**
     * 序列化器 与 序列化对象类型 的映射，key：序列化对象的类型，value：序列化器
     */
    private static final Map<Class<?>, Serializer<?>> SERIALIZER_MAP = new HashMap<>();

    /**
     * 序列化对象的类型 与 字节(表示类型) 的映射，key：序列化对象的类型对应的字节，value：序列化对象的类型
     */
    private static final Map<Byte, Class<?>> TYPE_MAP = new HashMap<>();

    static {
        // 注册所有序列化器
        for (Serializer<?> serializer : ServiceSupport.loadAll(Serializer.class)) {
            byte type = serializer.type();
            Class<?> eClass = serializer.getSerializeClass();
            SERIALIZER_MAP.put(eClass, serializer);
            TYPE_MAP.put(type, eClass);
            log.info("Found serializer, class: {}, type: {}.", eClass.getCanonicalName(), type);
        }
    }

    /**
     * 解析数据
     *
     * @param buffer 待解析的数据
     * @param <E>    解析后数据的类型
     * @return 解析后数据的对象
     */
    public static <E> E parse(byte[] buffer) {
        return parse(buffer, 0, buffer.length);
    }

    private static <E> E parse(byte[] buffer, int offset, int length) {
        byte type = parseEntryType(buffer);
        @SuppressWarnings("unchecked")
        Class<E> eClass = (Class<E>) TYPE_MAP.get(type);
        if (null == eClass) {
            throw new RuntimeException(String.format("Unknown entry type: %d!", type));
        } else {
            return parse(buffer, offset + 1, length - 1, eClass);
        }
    }

    // 解析条目的类型
    private static byte parseEntryType(byte[] buffer) {
        return buffer[0];
    }

    @SuppressWarnings("unchecked")
    private static <E> E parse(byte[] buffer, int offset, int length, Class<E> eClass) {
        Object entry = SERIALIZER_MAP.get(eClass).parse(buffer, offset, length);
        if (eClass.isAssignableFrom(entry.getClass())) {
            return (E) entry;
        } else {
            // TODO 抛出的异常可以细化为具体的异常，例如 SerializeException 等
            throw new RuntimeException("Type mismatch!");
        }
    }

    /**
     * 序列化数据
     *
     * @param entry 待序列化的数据
     * @param <E>   待序列化数据的类型
     * @return 序列化后的数据
     */
    public static <E> byte[] serialize(E entry) {
        @SuppressWarnings("unchecked")
        Serializer<E> serializer = (Serializer<E>) SERIALIZER_MAP.get(entry.getClass());
        if (serializer == null) {
            throw new RuntimeException(String.format("Unknown entry class type: %s", entry.getClass()));
        }

        byte[] bytes = new byte[serializer.size(entry) + 1];
        bytes[0] = serializer.type();
        serializer.serialize(entry, bytes, 1, bytes.length - 1);
        return bytes;
    }
}
